package web.struts.validator;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.validator.Field;
import org.apache.commons.validator.Validator;
import org.apache.commons.validator.ValidatorAction;
import org.apache.struts.action.ActionMessages;
import org.apache.struts.validator.validwhen.ValidWhen;

public class CustomFieldChecksEx {
	private static final long serialVersionUID = 1033442981535297127L;

	/**
	 * ログクラス。
	 */
	private static Log log = LogFactory.getLog(CustomFieldChecks.class);

	/**
	 * <p>
	 * 指定された値のチェックディジットをモジュラス10で判定する
	 * </p>
	 * ウェイトは"weight"パラメータで指定します。（指定の無い場合はデフォルトで"2"が使用されます）
	 * 
	 * @param obj
	 *            検査対象のオブジェクト
	 * @param va
	 *            <code>Validator</code>により用意された <code>ValidatorAction</code>
	 * @param field
	 *            フィールドオブジェクト
	 * @param errors
	 *            ActionMessages アクションエラー
	 * @param validator
	 *            Validatorインスタンス
	 * @param request
	 *            HTTPリクエスト
	 * @return 入力値が正しければ <code>true</code>
	 */
	public static boolean validateModulus10(Object obj, ValidatorAction va,
			Field field, ActionMessages errors, Validator validator,
			HttpServletRequest request) {
		return CustomFieldChecks.validateModulus10(obj, va, field, errors,
				validator, request);
	}

	/**
	 * <p>
	 * 指定された日付の逆転チェックを行う
	 * </p>
	 * チェック対象はyyyyMMddの西暦文字列とする
	 * 
	 * @param obj
	 *            検査対象のオブジェクト
	 * @param va
	 *            <code>Validator</code>により用意された <code>ValidatorAction</code>
	 * @param field
	 *            フィールドオブジェクト
	 * @param errors
	 *            ActionMessages アクションエラー
	 * @param validator
	 *            Validatorインスタンス
	 * @param request
	 *            HTTPリクエスト
	 * @return 入力値が正しければ <code>true</code>
	 */
	public static boolean validateDateOrder(Object obj, ValidatorAction va,
			Field field, ActionMessages errors, Validator validator,
			HttpServletRequest request) {

		return CustomFieldChecks.validateDateOrder(obj, va, field, errors,
				validator, request);
	}

	/**
	 * <p>
	 * 指定された和暦文字列の妥当性をチェックする。
	 * </p>
	 * 対象は和暦文字列とし、元号コードのプロパティ名は、"gengoCodeProperty"パラメータで指定します。
	 * 
	 * @param obj
	 *            検査対象のオブジェクト
	 * @param va
	 *            <code>Validator</code>により用意された <code>ValidatorAction</code>
	 * @param field
	 *            フィールドオブジェクト
	 * @param errors
	 *            ActionMessages アクションエラー
	 * @param validator
	 *            Validatorインスタンス
	 * @param request
	 *            HTTPリクエスト
	 * @return 入力値が正しければ <code>true</code>
	 */
	public static boolean validateSignedNumber(Object obj, ValidatorAction va,
			Field field, ActionMessages errors, Validator validator,
			HttpServletRequest request) {
		return CustomFieldChecks.validateSignedNumber(obj, va, field, errors,
				validator, request);
	}

	/**
	 * <p>
	 * 指定された数値の範囲を検証する
	 * </p>
	 * 範囲指定は符号、マイナス値も指定可能です
	 * 
	 * @param obj
	 *            検査対象のオブジェクト
	 * @param va
	 *            <code>Validator</code>により用意された <code>ValidatorAction</code>
	 * @param field
	 *            フィールドオブジェクト
	 * @param errors
	 *            ActionMessages アクションエラー
	 * @param validator
	 *            Validatorインスタンス
	 * @param request
	 *            HTTPリクエスト
	 * @return 入力値が正しければ <code>true</code>
	 */
	public static boolean validateSignedNumberRange(Object bean,
			ValidatorAction va, Field field, ActionMessages errors,
			Validator validator, HttpServletRequest request) {
		return CustomFieldChecks.validateSignedNumberRange(bean, va, field,
				errors, validator, request);
	}

	/**
	 * 指定された文字列のチェックディジットが正しいかを判定する。
	 * 
	 * @param code
	 *            検証対象文字列
	 * @param weight
	 *            ウェイト
	 * @return チェックディジットが正しいか否か
	 */
	public static boolean isValidModulus10(String code, int weight) {
		return CustomFieldChecks.isValidModulus10(code, weight);
	}

	/**
	 * <p>
	 * 時間の時と時間の分の関連チェック
	 * </p>
	 * 時間の時と時間の分いずれかが入力されている場合、すべて入力が必要です
	 * 
	 * @param obj
	 *            検査対象のオブジェクト
	 * @param va
	 *            <code>Validator</code>により用意された <code>ValidatorAction</code>
	 * @param field
	 *            フィールドオブジェクト
	 * @param errors
	 *            ActionMessages アクションエラー
	 * @param validator
	 *            Validatorインスタンス
	 * @param request
	 *            HTTPリクエスト
	 * @return 入力値が正しければ <code>true</code>
	 */
	public static boolean validateHourAndMinute(Object obj, ValidatorAction va,
			Field field, ActionMessages errors, Validator validator,
			HttpServletRequest request) {
		return CustomFieldChecks.validateHourAndMinute(obj, va, field, errors,
				validator, request);
	}

	/**
	 * <p>
	 * なしとありのチェックボックスが同時選択するチェック
	 * </p>
	 * なしとありのチェックボックスが不能同時選択する
	 * 
	 * @param obj
	 *            検査対象のオブジェクト
	 * @param va
	 *            <code>Validator</code>により用意された <code>ValidatorAction</code>
	 * @param field
	 *            フィールドオブジェクト
	 * @param errors
	 *            ActionMessages アクションエラー
	 * @param validator
	 *            Validatorインスタンス
	 * @param request
	 *            HTTPリクエスト
	 * @return 入力値が正しければ <code>true</code>
	 */
	public static boolean validateMultiChecked(Object obj, ValidatorAction va,
			Field field, ActionMessages errors, Validator validator,
			HttpServletRequest request) {
		return CustomFieldChecks.validateMultiChecked(obj, va, field, errors,
				validator, request);
	}

	/**
	 * 配列・コレクションの要素を検証するメソッドを取得する。
	 * 
	 * <b>このメソッドはアクションフォームを対象としているため フォーム以外で、流用を行なうことを推奨しない。</b>
	 * 
	 * @param va
	 *            Strutsにより用意された<code>ValidatorAction</code>
	 * @param paramClass
	 *            引数クラス配列
	 * @return 検証メソッドオブジェクト
	 */
	protected static Method getMethod(ValidatorAction va, Class[] paramClass) {

		String methodNameSource = va.getName();
		if (methodNameSource == null || "".equals(methodNameSource)) {
			// メソッド名指定がnullまたは空文字のときnull返却。
			return null;
		}

		// name属性から"Array"を除去したメソッド名を生成する
		// xxxxArray→validateXxxx
		char[] chars = methodNameSource.toCharArray();
		chars[0] = Character.toUpperCase(chars[0]);
		String validate = "validate" + new String(chars);
		String methodName = validate.substring(0, validate.length()
				- "Array".length());

		Method method = null;
		try {
			method = CustomFieldChecksEx.class
					.getMethod(methodName, paramClass);
		} catch (NoSuchMethodException e) {
			try {
				method = ValidWhen.class.getMethod(methodName, paramClass);
			} catch (NoSuchMethodException e1) {
				log.error("", e);
				log.error("", e1);
				return null;
			}
		}
		return method;
	}

}
